package nirvana.core.context;

import lombok.extern.slf4j.Slf4j;
import nirvana.core.security.SecurityCredential;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Locale;

/**
 * WebContext
 *
 * @author linkanyway
 * @version 1.0
 * @date 2023/11/27 18:51
 */
@Slf4j
@Component
public final class WebContext implements ApplicationContextAware {

    /**
     * application context
     */
    public static ApplicationContext context;

    /**
     * environment
     */
    public static Environment environment;


    /**
     * security information
     */
    private static final ThreadLocal<SecurityCredential> THREAD_PRINCIPAL = new ThreadLocal<> ();

    /**
     * todo: micro-service
     * request id
     */
    private static final ThreadLocal<Long> THREAD_REQUEST_ID = new ThreadLocal<> ();


    /**
     * localization information
     */
    private static final ThreadLocal<Locale> THREAD_LOCALES = new ThreadLocal<> ();

    /**
     * get locale for current context
     * Locale.getDefault ();
     */
    public static final Locale DEFAULT_LOCALE = Locale.getDefault ();


    /**
     * no access
     */
    private WebContext() {
    }

    /**
     * get current locale setting
     *
     * @return locale {@link Locale}
     */
    public static Locale currentLocale() {
        Locale locale = THREAD_LOCALES.get ();
        if (locale == null) {
            locale = DEFAULT_LOCALE;
        }
        return locale;
    }


    /**
     * get security credential for current request
     *
     * @return security credential {@link SecurityCredential}
     */
    public static SecurityCredential getThreadPrincipal() {
        return THREAD_PRINCIPAL.get ();
    }


    /**
     * set security credential for current request
     *
     * @param loginInfo credential {@link SecurityCredential}
     */
    public static void setThreadPrincipal(SecurityCredential loginInfo) {
        THREAD_PRINCIPAL.set (loginInfo);
    }


    /**
     * set locale for current request
     *
     * @param locale
     */
    public static void setLocale(Locale locale) {
        THREAD_LOCALES.set (locale);
    }


    /**
     * get request id for current request
     *
     * @return
     */
    public static Long getRequestId() {
        return THREAD_REQUEST_ID.get ();
    }


    /**
     * set request id for current request
     *
     * @param id unique request id
     */
    public static void setRequestId(Long id) {

        THREAD_REQUEST_ID.set (id);
    }


    /**
     * return user id  for current request
     *
     * @return user id
     */
    public static Long getCurrentUserId() {
        Long id = 0L;
        if (THREAD_PRINCIPAL.get () != null) {
            id = THREAD_PRINCIPAL.get ().getId ();
        }
        return id;
    }


    /**
     * get bean by name from springboot container
     *
     * @param name bean name
     * @return bean instance
     */
    public static Object getBean(String name) {
        return context.getBean (name);
    }

    /**
     * get bean by type
     *
     * @param type bean type
     * @return bean instance
     */
    public static Object getBean(Class<?> type) {

        return context.getBean (type);
    }


    /**
     * clean all cache in thread (eg: tomcat)
     */
    public static void remove() {
        THREAD_REQUEST_ID.remove ();
        THREAD_PRINCIPAL.remove ();
        THREAD_LOCALES.remove ();
    }


    /**
     * setup application context
     *
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws BeansException beansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
        environment = applicationContext.getEnvironment ();
    }
}
